package com.starsea.book.ui.widget

import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.text.Editable
import android.text.InputFilter
import android.text.InputType
import android.text.TextUtils
import android.text.TextWatcher
import android.text.method.HideReturnsTransformationMethod
import android.text.method.PasswordTransformationMethod
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.blankj.utilcode.util.KeyboardUtils
import com.starsea.book.R

/**
 * @author Lee
 * @createTime 2024-07-11 10 GMT+8
 * @desc :
 */
class VerifyEditText @JvmOverloads constructor(
  context: Context,
  attrs: AttributeSet? = null,
  defStyleAttr: Int = 0,
) : LinearLayout(context, attrs, defStyleAttr) {
  private val mTextViewList: MutableList<TextView> = ArrayList()
  private val mRelativeLayouts: MutableList<RelativeLayout> = mutableListOf()
  private val mCursorViews: MutableList<View> = mutableListOf()
  private var mShowCursor = false
  private var mCursorColor: Int = Color.parseColor("#FFFFFF")
  private var mEditText: EditText? = null
  private var drawableNormal: Drawable? = null
  private var drawableSelected: Drawable? = null
  private var mContext: Context? = null
  private var valueAnimator: ValueAnimator? = null
  private var mItemCount = 0

  //输入完成监听
  private var mInputCompleteListener: InputCompleteListener? = null

  init {
    init(context, attrs)
  }

  private fun init(context: Context, attrs: AttributeSet?) {
    mContext = context
    orientation = HORIZONTAL
    gravity = Gravity.CENTER
    @SuppressLint("CustomViewStyleable")
    val obtainStyledAttributes =
      getContext().obtainStyledAttributes(attrs, R.styleable.verify_EditText)
    drawableNormal =
      obtainStyledAttributes.getDrawable(R.styleable.verify_EditText_verify_background_normal)
    drawableSelected =
      obtainStyledAttributes.getDrawable(R.styleable.verify_EditText_verify_background_selected)
    val textColor = obtainStyledAttributes.getColor(
      R.styleable.verify_EditText_verify_textColor,
      ContextCompat.getColor(context, android.R.color.black)
    )
    mItemCount = obtainStyledAttributes.getInt(
      R.styleable.verify_EditText_verify_count,
      DEFAULT_ITEM_COUNT
    )
    val inputType = obtainStyledAttributes.getInt(
      R.styleable.verify_EditText_verify_inputType,
      InputType.TYPE_CLASS_NUMBER
    )
    val passwordVisibleTime = obtainStyledAttributes.getInt(
      R.styleable.verify_EditText_verify_password_visible_time,
      DEFAULT_PASSWORD_VISIBLE_TIME
    )
    val width = obtainStyledAttributes.getDimension(
      R.styleable.verify_EditText_verify_width,
      DEFAULT_ITEM_WIDTH.toFloat()
    ).toInt()
    val height =
      obtainStyledAttributes.getDimension(R.styleable.verify_EditText_verify_height, 0f)
        .toInt()
    val cursorWidth = obtainStyledAttributes.getDimension(
      R.styleable.verify_EditText_cursor_width,
      1F
    ).toInt()
    mCursorColor = obtainStyledAttributes.getColor(
      R.styleable.verify_EditText_cursor_color,
      ContextCompat.getColor(context, android.R.color.black)
    )
    mShowCursor =
      obtainStyledAttributes.getBoolean(R.styleable.verify_EditText_show_cursor, false)
    val cursorHeight = obtainStyledAttributes.getDimension(
      R.styleable.verify_EditText_cursor_height,
      20F
    ).toInt()
    val margin = obtainStyledAttributes.getDimension(
      R.styleable.verify_EditText_verify_margin,
      DEFAULT_ITEM_MARGIN.toFloat()
    ).toInt()
    val textSize = px2sp(
      context,
      obtainStyledAttributes.getDimension(
        R.styleable.verify_EditText_verify_textSize,
        sp2px(context, DEFAULT_ITEM_TEXT_SIZE.toFloat()).toFloat()
      )
    ).toFloat()
    val password =
      obtainStyledAttributes.getBoolean(R.styleable.verify_EditText_verify_password, false)
    obtainStyledAttributes.recycle()
    if (mItemCount < 2) mItemCount = 2 //最少 2 个 item
    mEditText = EditText(context)
    mEditText?.run {
      mEditText?.inputType = inputType
      layoutParams = LayoutParams(1, 1)
      isCursorVisible = false
      background = null
      filters = arrayOf<InputFilter>(InputFilter.LengthFilter(mItemCount)) //限制输入长度为 count
      addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(
          s: CharSequence,
          start: Int,
          count: Int,
          after: Int,
        ) {
        }

        override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
          if (before == 0 && (start + count) < 7) {// 输入
            if (count > 1) {// 有复制内容进来
              for (i in start until start + count) {
                val input = s.subSequence(i, i + 1) // 获取新输入的字
                inputText(i, password, passwordVisibleTime, input.toString())
              }
            } else {// 逐步输入
              inputText(
                start,
                password,
                passwordVisibleTime,
                s.subSequence(start, s.length).toString()
              )
            }
          } else {// 删除
            val textView = mTextViewList[start] // 获取对应的 textview
            textView.text = ""
            setTextViewBackground(textView, drawableNormal)
          }
          if (mInputCompleteListener != null && s.length == mTextViewList.size)
            mInputCompleteListener?.complete(
              s.toString()
            )
        }

        override fun afterTextChanged(s: Editable) {
          setCursorColor()
        }
      })
    }
    addView(mEditText)
    //点击弹出软键盘
    setOnClickListener { v: View? ->
      mEditText?.requestFocus()
      showSoftKeyBoard()
    }
    //遍历生成 textview
    for (i in 0 until mItemCount) {
      val relativeLayout = RelativeLayout(context)
      relativeLayout.layoutParams = getRelativeLayoutParams(i, margin, width, height)
      mRelativeLayouts.add(relativeLayout)

      val textView = TextView(context)
      textView.textSize = textSize
      textView.maxEms = 1
      textView.maxLines = 1
//            textView.gravity = Gravity.CENTER
      textView.setTextColor(textColor)
//            textView.layoutParams = layoutParams
      initTextView(textView)
      setTextViewBackground(textView, drawableNormal)
//            addView(textView)
      relativeLayout.addView(textView)
      mTextViewList.add(textView)

      if (mShowCursor) {
        val cursorView = View(context)
        initCursorView(cursorView, cursorWidth, cursorHeight)
        relativeLayout.addView(cursorView)
        mCursorViews.add(cursorView)
      }
      relativeLayout.setBackgroundColor(Color.BLACK)
      addView(relativeLayout)
    }

    setCursorColor()
  }

  private fun getRelativeLayoutParams(
    i: Int,
    margin: Int,
    width: Int,
    height: Int,
  ): LayoutParams {
    val layoutParams = LayoutParams(
      width,
      if (height == 0) ViewGroup.LayoutParams.WRAP_CONTENT else height
    )
    if (i == 0) layoutParams.leftMargin = -1 else layoutParams.leftMargin = margin
    return layoutParams
  }

  private fun initTextView(textView: TextView) {
    val lp: RelativeLayout.LayoutParams = RelativeLayout.LayoutParams(
      ViewGroup.LayoutParams.MATCH_PARENT,
      ViewGroup.LayoutParams.MATCH_PARENT
    )
    textView.gravity = Gravity.CENTER
    textView.layoutParams = lp
  }

  private fun initCursorView(cursorView: View, cursorWidth: Int, cursorHeight: Int) {
    val lp: RelativeLayout.LayoutParams = RelativeLayout.LayoutParams(
      cursorWidth,
      cursorHeight
    )
    lp.addRule(RelativeLayout.ALIGN_PARENT_START)
    lp.addRule(RelativeLayout.CENTER_VERTICAL)
    lp.marginStart = 6
    cursorView.layoutParams = lp
  }

  private fun inputText(start: Int, password: Boolean, passwordVisibleTime: Int, input: String) {
    val textView = mTextViewList[start] // 获取对应的 textview
    textView.text = input
    if (password) { //如果需要密文显示
      textView.transformationMethod =
        HideReturnsTransformationMethod.getInstance()
      //passwordVisibleTime 毫秒后设置为密文显示
      textView.postDelayed(
        {
          textView.transformationMethod =
            PasswordTransformationMethod.getInstance()
        },
        passwordVisibleTime.toLong()
      )
    }
    setTextViewBackground(textView, drawableSelected)
  }

  /**
   * view 添加到窗口时，延迟 500ms 弹出软键盘
   */
  override fun onAttachedToWindow() {
    super.onAttachedToWindow()
    mEditText?.postDelayed({ showSoftKeyBoard() }, 500)
  }

  /**
   * 设置背景
   * @param textView
   * @param drawable
   */
  private fun setTextViewBackground(textView: TextView, drawable: Drawable?) {
    if (drawable != null) textView.background = drawable
  }

  private fun setCursorColor() {
    if (mShowCursor) {
      valueAnimator?.cancel()

      for (i in 0 until mItemCount) {
        val cursorView = mCursorViews[i]
        cursorView.setBackgroundColor(Color.TRANSPARENT)
      }

      val index = mEditText?.text?.length ?: 0
      if (index < mItemCount) {
        setCursorView(mCursorViews[index])
      }
    }
  }

  /**
   * 设置焦点色变换动画
   *
   * @param view
   */
  private fun setCursorView(view: View) {
    this.valueAnimator = ObjectAnimator.ofInt(
      view,
      "backgroundColor",
      mCursorColor,
      android.R.color.transparent
    )
    valueAnimator?.run {
      duration = 1500
      repeatCount = -1
      repeatMode = ValueAnimator.RESTART
      setEvaluator { fraction, startValue, endValue -> if (fraction <= 0.5f) startValue else endValue }
      start()
    }
  }

  /**
   * 获取当前输入的内容
   *
   * @return
   */
  val content: String
    get() {
      val text = mEditText?.text
      return if (TextUtils.isEmpty(text)) "" else mEditText?.text.toString()
    }

  /**
   * 清除内容
   */
  fun clearContent() {
    mEditText?.setText("")
    for (i in mTextViewList.indices) {
      val textView = mTextViewList[i]
      textView.text = ""
      setTextViewBackground(textView, drawableNormal)
    }
  }

  /**
   * 设置默认的内容
   *
   * @param content
   */
  fun setDefaultContent(content: String) {
    mEditText?.setText(content)
    mEditText?.requestFocus()
    val chars = content.toCharArray()
    val min = Math.min(chars.size, mTextViewList.size)
    for (i in 0 until min) {
      val aChar = chars[i]
      val s = aChar.toString()
      val textView = mTextViewList[i]
      textView.text = s
      setTextViewBackground(textView, drawableSelected)
    }
    if (mInputCompleteListener != null && min == mTextViewList.size) mInputCompleteListener?.complete(
      content.substring(0, min)
    )
  }

  /**
   * 显示软键盘
   */
  private fun showSoftKeyBoard() {
    val imm = mContext?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    imm.showSoftInput(mEditText, InputMethodManager.SHOW_FORCED)
  }

  /**
   * 添加输入完成的监听
   *
   * @param inputCompleteListener
   */
  fun addInputCompleteListener(inputCompleteListener: InputCompleteListener) {
    mInputCompleteListener = inputCompleteListener
    val content = mEditText?.text
    if (!TextUtils.isEmpty(content) && content.toString().length == mTextViewList.size) {
      mInputCompleteListener?.complete(content.toString())
    }
  }

  interface InputCompleteListener {
    fun complete(content: String)
  }

  private fun px2sp(context: Context, pxValue: Float): Int {
    val fontScale = context.resources.displayMetrics.scaledDensity
    return (pxValue / fontScale + 0.5f).toInt()
  }

  private fun sp2px(context: Context, spValue: Float): Int {
    val fontScale = context.resources.displayMetrics.scaledDensity
    return (spValue * fontScale + 0.5f).toInt()
  }

  override fun onDetachedFromWindow() {
    super.onDetachedFromWindow()
//    CommonUtil.hideKeyboard(this)
    KeyboardUtils.hideSoftInput(this)
    valueAnimator?.cancel()
  }


  companion object {
    //默认 item 个数为 4 个
    private const val DEFAULT_ITEM_COUNT = 4

    //默认每个 item 的宽度为 100
    private const val DEFAULT_ITEM_WIDTH = 100

    //默认每个 item 的间距为 50
    private const val DEFAULT_ITEM_MARGIN = 50

    //默认每个 item 的字体大小为 14
    private const val DEFAULT_ITEM_TEXT_SIZE = 14

    //默认密码明文显示时间为 200ms，之后密文显示
    private const val DEFAULT_PASSWORD_VISIBLE_TIME = 200
  }
}